package main

import "fmt"

type Tag struct {
	ID   int64 // tag的主键
	Name string
}
type Operation interface {
	add(addTag []Tag)
	del(addTag []Tag)
	list() []Tag
}

type TagOperation struct {
	Tags  map[int64]Tag
	Order []int64
}

func (t *TagOperation) list() []Tag {
	newTag := make([]Tag, 0, len(t.Tags))
	for _, id := range t.Order {
		newTag = append(newTag, t.Tags[id])
	}
	return newTag
}

func NewTagOperation(tags []Tag) Operation {
	tagMap := make(map[int64]Tag)
	order := []int64{}
	for _, tag := range tags {
		tagMap[tag.ID] = tag
		order = append(order, tag.ID)
	}
	return &TagOperation{
		Tags:  tagMap,
		Order: order,
	}
}

func (t *TagOperation) add(addTags []Tag) {
	for _, addTag := range addTags {
		if _, ok := t.Tags[addTag.ID]; ok {
			t.Tags[addTag.ID] = addTag
		} else {
			t.Tags[addTag.ID] = addTag
			t.Order = append(t.Order, addTag.ID)
		}
	}

}

func (t *TagOperation) del(delTags []Tag) {
	for _, delTag := range delTags {
		delete(t.Tags, delTag.ID)
		for i, id := range t.Order {
			if id == delTag.ID {
				copy(t.Order[i:], t.Order[i+1:])
				t.Order = t.Order[:len(t.Order)-1]
				break
			}
		}
	}
}

func main() {
	tags := []Tag{
		{ID: 1, Name: "a"},
		{ID: 4, Name: "b"},
		{ID: 3, Name: "c"},
	}
	tagOp := NewTagOperation(tags)

	newTags := []Tag{
		{ID: 2, Name: "d"},
		{ID: 1, Name: "e"},
	}
	tagOp.add(newTags)

	delTags := []Tag{
		{ID: 3, Name: "c"},
	}
	tagOp.del(delTags)
	for i := 0; i < 10; i++ {

		fmt.Println(tagOp.list())
	}
}
